package com.xiaoyu.base.data;

import android.text.TextUtils;

import com.xiaoyu.net.request.RequestWithJsonDataReturn;
import com.xiaoyu.base.DBCall;

import in.srain.cube.concurrent.AppThreads;

import com.xiaoyu.base.entity.UserEntity;
import com.xiaoyu.base.model.User;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import in.srain.cube.request.JsonData;
import in.srain.cube.request.RequestData;
import in.srain.cube.request.RequestDefaultHandler;
import in.srain.cube.util.CLog;

public class UserInfoDataProvider {

    private static final String TAG = UserInfoDataProvider.class.getSimpleName();
    private static final UserInfoDataProvider INSTANCE = new UserInfoDataProvider();
    private static String sUserGetBasicApi;

    private Map<String, User> mUserMap;

    private UserInfoDataProvider() {
        mUserMap = new ConcurrentHashMap<>();
    }

    public static UserInfoDataProvider getInstance() {
        return INSTANCE;
    }

    public static void init(String userGetBasicApi) {
        sUserGetBasicApi = userGetBasicApi;
    }

    private void syncUserFromServer(Collection<String> uids) {
        CLog.d(TAG, "syncUserFromServer: %s", uids.size());
        final RequestWithJsonDataReturn<JsonData> request = new RequestWithJsonDataReturn<>();
        RequestData requestData = request.getRequestData().setRequestUrl(sUserGetBasicApi);
        requestData.addPostData("ids", TextUtils.join(",", uids));
        request.setRequestHandler(new RequestDefaultHandler<JsonData, JsonData>() {
            @Override
            public JsonData processOriginData(JsonData originData) {
                List<JsonData> rawList = originData.optJson("data").toList();
                updateFromJsonList(rawList);
                return originData;
            }
        });
        try {
            request.requestSync();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }

    public void updateFromJson(JsonData jsonData) {
        final String uid = jsonData.optString("id");
        if (TextUtils.isEmpty(uid)) {
            return;
        }
        User user = User.fromJson(jsonData);
        mUserMap.put(user.getUid(), user);
        AppThreads.runOnDBThread(() -> {
            DBCall.run(database -> database.userDao().upsert(user.toEntity()));
        });
    }

    public void updateFromJsonList(List<JsonData> rawList) {
        final List<UserEntity> entityList = new LinkedList<>();
        for (JsonData item : rawList) {
            final String uid = item.optString("id");
            if (!TextUtils.isEmpty(uid)) {
                UserEntity entity = new UserEntity(item);
                User user = User.fromUserEntity(entity);
                entityList.add(entity);
                mUserMap.put(user.getUid(), user);
            }
        }
        AppThreads.runOnDBThread(() -> DBCall.run(database -> database.userDao().upsertList(entityList)));
    }

    public void updateUser(User newUser) {
        if (newUser.isNobody()) {
            return;
        }

        User oldUser = mUserMap.get(newUser.getUid());
        if (oldUser != null) {
            oldUser.tryToUpdateFrom(newUser);
        }
        mUserMap.put(newUser.getUid(), newUser);
        AppThreads.runOnDBThread(() -> DBCall.run(database -> database.userDao().upsert(newUser.toEntity())));
    }

    public void updateUserList(List<User> userList) {
        AppThreads.runOnDBThread(() -> {
            final List<UserEntity> entityList = new LinkedList<>();
            for (User user : userList) {
                if (!user.isNobody()) {
                    entityList.add(user.toEntity());
                    mUserMap.put(user.getUid(), user);
                }
            }
            DBCall.run(database -> database.userDao().upsertList(entityList));
        });
    }

    public User ensureAndGetUser(String uid) {
        ensureUser(uid);
        return fetchFromMemory(uid);
    }

    public User fetchFromMemory(String uid) {
        if (TextUtils.isEmpty(uid)) {
            return User.NOBODY;
        }
        User user = mUserMap.get(uid);
        if (user == null) {
            user = User.NOBODY;
        }
        return user;
    }

    public void ensureUser(String uid) {
        ensureUser(Collections.singleton(uid));
    }

    public void ensureUser(Set<String> uids) {
        Set<String> needFetchUids = new HashSet<>();

        for (String uid : uids) {
            if (TextUtils.isEmpty(uid)) {
                continue;
            }
            if (mUserMap.containsKey(uid)) {
                continue;
            }

            User user = User.loadFromDb(uid);
            if (user != null && !user.isNobody()) {
                mUserMap.put(uid, user);
            } else {
                needFetchUids.add(uid);
            }
        }

        if (!needFetchUids.isEmpty()) {
            syncUserFromServer(needFetchUids);
        }
    }
}
